package com.brillilab.service.core.notice.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.brillilab.common.alioss.OssFileEnum;
import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.entity.PageVo;
import com.brillilab.common.exceptions.BrillilabException;
import com.brillilab.dao.mapper.notice.NoticeMapper;
import com.brillilab.domain.enums.notice.NoticeEnum;
import com.brillilab.domain.pa.notice.NoticePa;
import com.brillilab.domain.po.lab.Lab;
import com.brillilab.domain.po.notice.Notice;
import com.brillilab.domain.po.notice.NoticeRead;
import com.brillilab.domain.po.system.FileManage;
import com.brillilab.domain.vo.lab.LabMemberVo;
import com.brillilab.domain.vo.notice.NoticeDetail;
import com.brillilab.domain.vo.notice.NoticeSearch;
import com.brillilab.domain.vo.notice.NoticeVo;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.core.lab.ILabMemberService;
import com.brillilab.service.core.lab.ILabService;
import com.brillilab.service.core.notice.INoticeReadService;
import com.brillilab.service.core.notice.INoticeService;
import com.brillilab.service.core.system.IFileManageService;
import com.brillilab.service.module.message.producer.MessageProducer;
import com.brillilab.service.module.message.template.impl.announcement.PublicAnnouncementTemp;
import com.github.pagehelper.PageHelper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 公告
 *
 * @author wmh
 */
@Service
@Transactional
public class NoticeServiceImpl implements INoticeService {

    @Resource
    private NoticeMapper noticeMapper;
    @Resource
    private INoticeReadService noticeReadService;
    @Resource
    private IFileManageService fileManageService;
    @Resource
    private ILabService labService;
    @Resource
    private ILabMemberService labMemberService;
    @Resource
    private MessageProducer messageProducer;

    @Override
    public Notice insert(Notice notice) {
        Assert.notNull(notice,"参数缺失！");
        Assert.isTrue(noticeMapper.insert(notice) == 1,"操作失败！");
        return notice;
    }

    @Override
    public Notice update(Notice notice) {
        Assert.isTrue(notice != null && notice.getId() != null,"参数缺失！");
        Assert.isTrue(noticeMapper.updateById(notice) == 1,"操作失败！");
        return notice;
    }

    @Override
    public Boolean delete(Long id,Long labId) {
        Assert.isTrue(id != null && labId != null,"参数缺失！");
        Notice notice=this.selectOne(id,labId);
        Assert.notNull(notice,"通知不存在或已删除！");
        int i=noticeMapper.deleteById(id);
        return i == 1;
    }

    @Override
    public Notice selectOne(Long noticeId,Long labId) {
        Assert.isTrue(noticeId != null && labId != null,"参数缺失！");
        return noticeMapper.selectOne(new LambdaQueryWrapper<Notice>()
                .eq(Notice::getId,noticeId)
                .eq(Notice::getLabId,labId)
                .eq(Notice::getIsDelete,0));
    }

    @Override
    public List<Notice> selectList(Long labId) {
        Assert.notNull(labId,"参数缺失！");
        return noticeMapper.selectList(new LambdaQueryWrapper<Notice>()
                .eq(Notice::getLabId,labId)
                .eq(Notice::getIsDelete,0));
    }

    @Override
    public NoticeDetail selectNoticeDetail(Long id,Long labId) {
        Assert.isTrue(id != null && labId != null,"参数缺失！");
        return noticeMapper.selectNoticeDetail(id,labId);
    }

    @Override
    public Notice publishNoticeNew(NoticePa noticePa, UserInfoVo userInfo) {
        Assert.isTrue(noticePa != null && userInfo != null,"参数缺失！");

        //插入公告信息
        Notice notice=new Notice();
        BeanUtils.copyProperties(noticePa,notice);
        notice.setLabId(userInfo.getLabId());
        notice.setUserName(userInfo.getName());
        Notice insert=this.insert(notice);

        //获取指定附件ID的附件列表
        if(noticePa.getAttachment()!=null && noticePa.getAttachment().length>0){
            List<FileManage> fileManageList=fileManageService.selectList(noticePa.getAttachment());
            Assert.isTrue(CollectionUtils.isNotEmpty(fileManageList),"附件不存在或已被删除！");

            //绑定附件与公告的关系
            for (FileManage fileManage:fileManageList) {
                if(fileManage!=null && fileManage.getReferDataId()==0){
                    //更新数据关联ID
                    fileManage.setReferDataId(insert.getId());
                    fileManage.setUpdateTime(new Date());
                    fileManageService.updateById(fileManage);
                }
            }
        }

        //推送
        sendNoticeMessagePush(userInfo,insert);

        return insert;
    }

    @Override
    public Notice editNoticeNew(NoticePa noticePa,UserInfoVo userInfo) {
        Assert.isTrue(noticePa != null && userInfo != null && noticePa.getId() != null,"参数缺失！");

        Notice exist=this.selectOne(noticePa.getId(),userInfo.getLabId());

        Assert.notNull(exist,"通知不存在！");

        if(StringUtils.isNotBlank(noticePa.getDescription())){
            exist.setDescription(noticePa.getDescription());
        }

        if(noticePa.getAttachment()!=null && noticePa.getAttachment().length>0){
        	fileManageService.relevanceBatch(noticePa.getAttachment(), exist.getId(), OssFileEnum.Announcement, userInfo.getLabId(), userInfo.getId());
        }

        exist.setUpdateTime(new Date());
        return this.update(exist);

    }

    /**
     * 发布公告
     *
     * @param noticePa
     * @param userInfo
     * @return
     */
    @Override
    public Notice publishNotice(NoticePa noticePa, UserInfoVo userInfo) {

        Assert.isTrue(noticePa != null && userInfo != null,"参数缺失！");

        //插入公告信息
        Notice notice=new Notice();
        BeanUtils.copyProperties(noticePa,notice);
        notice.setLabId(userInfo.getLabId());
        notice.setUserName(userInfo.getName());
        Notice insert=this.insert(notice);

        //插入正式附件
        if(noticePa.getAttachment()!=null && noticePa.getAttachment().length!=0){
            fileManageService.relevanceBatch(noticePa.getAttachment(), insert.getId(), OssFileEnum.Announcement, userInfo.getLabId(), userInfo.getId());
        }

        //推送
        sendNoticeMessagePush(userInfo,insert);

        return insert;
    }

    private void sendNoticeMessagePush(UserInfoVo userInfo,Notice insert) {
        //发布公告，执行消息推送,推送给实验室所有成员
        List<LabMemberVo> labMemberVos=labMemberService.selectList(userInfo.getLabId(),1);
        Map<Long,Long> idMap=labMemberVos.stream().filter(m -> !m.getUserId().equals(userInfo.getId())).collect(Collectors.toMap(LabMemberVo::getUserId,LabMemberVo::getLabMemberId));

        Lab lab=labService.selectById(userInfo.getLabId());
        PublicAnnouncementTemp publicAnnouncementTemp=new PublicAnnouncementTemp(userInfo.getLabId(),idMap,userInfo.getName(),lab.getName(),insert.getId());
        messageProducer.sendMessagePushMutiReceiver(publicAnnouncementTemp);
    }


    /**
     * 公告列表(排序/搜索)
     *
     * @return
     */
    @Override
    public PageVo<NoticeVo> getAndSearchNoticeList(NoticeSearch noticeSearch) {

        int pageNum=noticeSearch.getPageNum() > 0 ? noticeSearch.getPageNum() : 1;
        int pageSize=noticeSearch.getPageSize() > 0 ? noticeSearch.getPageSize() : 10;
        
        PageHelper.startPage(pageNum, pageSize);
		List<NoticeVo> notices = noticeMapper.selectList(noticeSearch);
        return new PageVo<NoticeVo>(notices);
    }

    /**
     * 公告已读成员
     *
     * @param noticeId
     * @param labId
     * @return
     */
    @Override
    public List<LabMemberVo> selectReadMemberList(Long noticeId,Long labId) {

        Assert.isTrue(noticeId != null && labId != null,"参数缺失！");

        return noticeReadService.selectReadMemberList(noticeId,labId);
    }

    /**
     * 公告详情
     *
     * @param noticeId
     * @param userInfo
     * @return
     */
    @Override
    public NoticeDetail getNoticeDetailAndSetReadMember(Long noticeId,UserInfoVo userInfo) {

        Assert.isTrue(noticeId != null && userInfo != null,"参数缺失！");

        //查找通知详情
        NoticeDetail noticeDetail=this.selectNoticeDetail(noticeId,userInfo.getLabId());

        if(noticeDetail==null){
            throw new BrillilabException(ResultEnum.DATA_NOT_EXIST,"此条公告已被删除哦~");
        }

        Notice notice=noticeMapper.selectOne(
                new LambdaQueryWrapper<Notice>().eq(Notice::getId,noticeId).eq(Notice::getLabId,userInfo.getLabId()));

        //设置文件路径
        List<FileManage> fileList = fileManageService.selectList(OssFileEnum.Announcement,noticeDetail.getId());
        noticeDetail.setAttachments(fileList);

        //设置已读用户
        NoticeRead read = noticeReadService.selectOneByNoticeIdAndLabIdAndLabMemberId(noticeId,userInfo.getLabId(),userInfo.getLabMemberId());
        if(read==null){
            read=new NoticeRead();
            read.setLabId(userInfo.getLabId());
            read.setLabMemberId(userInfo.getLabMemberId());
            read.setNoticeId(noticeId);
            noticeReadService.insert(read);
        }

        //查找设置可以供使用的文件路径


        noticeMapper.updateById(notice);

        return noticeDetail;
    }

    /**
     * 编辑公告
     *
     * @param noticePa
     * @param userInfo
     * @return
     */
    @Override
    public Notice editeNotice(NoticePa noticePa,UserInfoVo userInfo) {

        Assert.isTrue(noticePa != null && userInfo != null && noticePa.getId() != null,"参数缺失！");

        Notice exist=this.selectOne(noticePa.getId(),userInfo.getLabId());

        Assert.notNull(exist,"通知不存在！");

        if(StringUtils.isNotBlank(noticePa.getDescription())){
            exist.setDescription(noticePa.getDescription());
        }

        if(noticePa.getAttachment() != null && noticePa.getAttachment().length != 0){
            //插入正式附件
            fileManageService.relevanceBatch(noticePa.getAttachment(), exist.getId(), OssFileEnum.Announcement, userInfo.getLabId(), userInfo.getId());
        }

        exist.setUpdateTime(new Date());

        return this.update(exist);
    }

    /**
     * 删除公告
     *
     * @param noticeId
     * @param isTop
     * @param userInfo
     * @return
     */
    @Override
    public Notice setTopNotice(Long noticeId,Integer isTop,UserInfoVo userInfo) {

        Assert.isTrue(noticeId != null && isTop != null && userInfo != null,"参数缺失！");

        Notice notice=this.selectOne(noticeId,userInfo.getLabId());

        Assert.notNull(notice,"公告不存在！");

        switch (isTop) {
            case 1:
                notice.setIsTop(NoticeEnum.IsTop.TRUE.getValue());
                break;
            default:
                notice.setIsTop(NoticeEnum.IsTop.FALSE.getValue());
                break;
        }
        notice.setUpdateTime(new Date());

        return this.update(notice);
    }

}
